package com.fr.plugin.export.xml.exporter;

import com.fr.base.Margin;
import com.fr.base.Style;
import com.fr.general.GeneralUtils;
import com.fr.io.exporter.AbstractAppExporter;
import com.fr.log.FineLoggerFactory;
import com.fr.main.FineBook;
import com.fr.main.workbook.ResultWorkBook;
import com.fr.page.*;
import com.fr.plugin.context.PluginContexts;
import com.fr.report.cell.CellElement;
import com.fr.report.cell.cellattr.CellGUIAttr;
import com.fr.report.elementcase.ElementGetter;
import com.fr.report.report.ECReport;
import com.fr.report.report.ResultReport;
import com.fr.report.stable.ReportSettings;
import com.fr.stable.EncodeConstants;
import com.fr.stable.StringUtils;
import com.sun.org.apache.xml.internal.serialize.OutputFormat;
import com.sun.org.apache.xml.internal.serialize.XMLSerializer;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
import java.text.Format;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class XmlExporter<T> extends AbstractAppExporter<T> {

    @Override
    public void export(OutputStream out, ResultWorkBook book) throws Exception {
        List paperSettingList = this.getPaperSettings(book, (Margin)null);
        for (int i = 0, len = book.getReportCount(); i < len; i++) {
            this.export(out, book.getResultReport(i), (PaperSettingProvider) paperSettingList.get(i));
        }
    }

    @Override
    public void export(OutputStream out, PageSetProvider pageSet) throws Exception {
        for (int i = 0; i < pageSet.size(); i++) {
            ReportPageProvider reportPage = pageSet.getPage(i);
            ClippedPageProvider page = this.pick(reportPage);
            if (page == null) {
                break;
            }
            this.exportReport(out, (ElementGetter) page, 0, (page).getRowCount());
        }
    }

    private void export(OutputStream out, ResultReport report, PaperSettingProvider paperSetting)
            throws Exception {
        if (report != null) {
            FineLoggerFactory.getLogger().info("UnLayerReport start export");
            exportReport(out, (ECReport) report, 0, (report).getRowCount());
        }
    }

    public void exportReport(OutputStream out, ElementGetter reportCase, int start, int end) throws Exception {
        if (PluginContexts.currentContext().isAvailable()) {
            PrintWriter writer = new PrintWriter(new OutputStreamWriter(out, EncodeConstants.ENCODING_UTF_8));
            StringBuilder xmlBuffer = new StringBuilder("");
//            xmlBuffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>");
//            xmlBuffer.append("<report>");
            for (int row = start; row < end; row++) {
//                xmlBuffer.append("<row>");
                Iterator it = reportCase.getRow(row);

                while (it.hasNext()) {
//                    xmlBuffer.append("<col>");
                    String exportText;
                    CellElement cell = (CellElement) it.next();
                    if (cell == null) {
                        exportText = StringUtils.EMPTY;
                    } else {
                        boolean export = this.isCellPrintable(cell);
                        if (export) {
                            Object value = cell.getValue();
                            Style style = cell.getStyle();
                            if (style != null) {
                                Format format = style.getFormat();
                                exportText = Style.valueToText(value, format);
                            } else {
                                exportText = GeneralUtils.objectToString(value);
                            }
                        } else {
                            exportText = StringUtils.EMPTY;
                        }
                    }
                    xmlBuffer.append(exportText);
//                    xmlBuffer.append("</col>");

                }
//                xmlBuffer.append("</row>");
            }
//            xmlBuffer.append("</report>");
            writer.println(formatXML(xmlBuffer.toString()));
            writer.flush();
        } else {
            throw new RuntimeException("XML Export Plugin License Expired!");
        }
    }

    public static List<PaperSettingProvider> getPaperSettings(FineBook book, Margin offsetMargin) {
        if (book == null) {
            return null;
        } else {
            List<PaperSettingProvider> list = new ArrayList();

            for(int i = 0; i < book.getReportCount(); ++i) {
                ReportSettingsProvider reportSettings = book.getReport(i).getReportSettings();
                if (reportSettings == null) {
                    reportSettings = ReportSettings.DEFAULTSETTINGS;
                }

                try {
                    PaperSettingProvider setting = (PaperSettingProvider)((ReportSettingsProvider)reportSettings).getPaperSetting().clone();
                    Margin margin = setting.getMargin();
                    if (offsetMargin != null) {
                        margin.setTop(margin.getTop().add(offsetMargin.getTop()));
                        margin.setLeft(margin.getLeft().add(offsetMargin.getLeft()));
                        margin.setBottom(margin.getBottom().subtract(offsetMargin.getBottom()));
                        margin.setRight(margin.getRight().subtract(offsetMargin.getRight()));
                    }

                    list.add(setting);
                } catch (CloneNotSupportedException var7) {
                    FineLoggerFactory.getLogger().error(var7.getMessage(), var7);
                    break;
                }
            }

            return list;
        }
    }

    public static ClippedPageProvider pick(ReportPageProvider reportPage) {
        if (reportPage == null) {
            return null;
        } else {
            ClippedPageProvider[] clippers = reportPage.getPages();
            if (clippers.length == 1 && clippers[0] != null) {
                ClippedPageProvider cp = clippers[0];
                cp.deriveResolution(96);
                return cp;
            } else {
                return null;
            }
        }
    }

    public static boolean isCellPrintable(CellElement cell) {
        if (cell == null) {
            return false;
        } else {
            CellGUIAttr gui = cell.getCellGUIAttr();
            return gui == null || gui.isPrintContent();
        }
    }

    public  String formatXML(String unformattedXml) {
        try {
            final Document document = parseXmlFile(unformattedXml);
            OutputFormat format = new OutputFormat(document);
            format.setLineWidth(65);
            format.setIndenting(true);
            format.setIndent(2);
            Writer out = new StringWriter();
            XMLSerializer serializer = new XMLSerializer(out, format);
            serializer.serialize(document);
            return out.toString();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private Document parseXmlFile(String in) {
        try {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            InputSource is = new InputSource(new StringReader(in));
            return db.parse(is);
        } catch (ParserConfigurationException e) {
            throw new RuntimeException(e);
        } catch (SAXException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}